package com.hxzy.security.handler;

import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.hxzy.common.TZXMConst;
import com.hxzy.common.util.ServletUtil;
import com.hxzy.common.vo.CodeEnum;
import com.hxzy.vo.system.HxzyUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * 自定义认证验证token是否有效，如果有效，模糊创建一个UsernamepasswordToken对象，交给spring security
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Value(value = "${token.jwtpwd}")
    private String jwtPwd;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //1、请求头中获取请求数据  Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImVkZGU2NGMwLTJkNDUtNDFmYS05Y2VlLTc5MDE4MTI2Yjc2ZiJ9.WoKYSKtxXR5yKsrIR0K7MMlqysEOsixVM1JCz2tbHT6ib_RHW1fWSX_HChr1ooLI3KmytxCzPwB_hdroUr87Lg
        String jwtToken = request.getHeader("Authorization");
        //2、如果请求头没有值，放行，交给springsecurity处理，否则就自己处理!
        if (StrUtil.isNotBlank(jwtToken) && !StrUtil.startWith(jwtToken,"Basic")) {
            //3、如果请求头有Authorization ， 判断值 是否有 Bearer(持票人单词，如果有删除，剩下的就是我们的jwt令牌)
            if (jwtToken.startsWith("Bearer ")) {
                jwtToken = jwtToken.replace("Bearer ", "");
            }

            //4、通hutool的jwt解析令牌取得uuid，如果有错误 输出json  令牌无效请重新登录
            if (!JWTUtil.verify(jwtToken, jwtPwd.getBytes(StandardCharsets.UTF_8))) {
                ServletUtil.outJson(response, CodeEnum.TOKEN_EXPIRED);
                return;
            }

            //5、令牌有效的，从数据库中 查询出这个令牌uuid对应的employee的信息 存储来（放哪里?）
            JWT jwt = JWTUtil.parseToken(jwtToken);
            String uuid = jwt.getPayload(TZXMConst.LOGIN_USER_KEY).toString();
            //去redis中查询
            String redisKey = TZXMConst.LOGIN_TOKEN_KEY + uuid;
            HxzyUser user = (HxzyUser) this.redisTemplate.opsForValue().get(redisKey);

            if (user == null) {
                ServletUtil.outJson(response, CodeEnum.TOKEN_EXPIRED);
                return;
            }

            //必须按照springsecurity方式来创建UserDetails对象,并且把这个对放入到SecurityContextHolder.getContext()
            //你的token在redis中，但是spring security认为你无效 (因为springsecurity默认使用session的，所有每一次都会帮你创建一个session)
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            //未认证，但是令牌在redis中有过的，说明登录过
            if (user != null && authentication == null){
                //验证token有效性，并且刷新token时间 (模拟创建一个认证的对象)
                UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
                authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            }
        }

        filterChain.doFilter(request, response);

    }

}
